package gov.nasa.anml.lifted;

import java.util.ArrayList;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.utility.SimpleBoolean;
import gov.nasa.anml.utility.SimpleObject;

public class Produce<T extends SimpleObject<? super T>> extends BinaryExpression<T,T,T> {

	public Produce(Expression<T, T> l, Expression<T, ?> r) {
		super(l, r);
	}

	public boolean apply(State p, int contextID, State c) {
		return false;
	}
	public T value(State s) {
		return null;
	}
	
	public void translateStmt(PDDL pddl, Interval unit, PDDL.Time part) {
		ArrayList<PDDL.BooleanExpression> conditions = unit.getPDDLConditions(); 
		ArrayList<PDDL.Effect> effects = unit.getPDDLEffects();

		PDDL.Time pl,pr;
		switch(part) {
		case Start:
		case End:
			pl = pr = part;
			break;
		default:
			pl = PDDL.Time.Start;
			pr = PDDL.Time.End;
			break;
		}
		
		switch(left.typeCode()) {
		case Boolean:
			assert right.typeCode() == TypeCode.Boolean : "No operation combines booleans and other types directly";
			PDDL.PredicateReference refB = (PDDL.PredicateReference) left.translateLValue(pddl,unit);
			if (right instanceof SimpleBoolean) {
				boolean v = ((SimpleBoolean)right).v;
				if (v) {
					conditions.add(pddl.wrap(pl,pddl.makeTest(refB,false)));
					effects.add(pddl.makeEffect(pl,refB,true));
					if (pl != pr)
						conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.makeTest(refB,true)));
				}
			} else {
				PDDL.BooleanExpression r = (PDDL.BooleanExpression) right.translateExpr(pddl,unit);
				conditions.add(pddl.wrap(pl,pddl.makeTest(PDDL.Op.or,pddl.negate(refB),pddl.negate(r))));
				effects.add(pddl.wrap(pl,pddl.makeEffect(r,refB,true)));
				// not easy to implement the interim portion
				// if we had upper and lower bounds on bools and floats then it wouldn't be so bad.
				//conditions.add(pddl.wrap(PDDL.Time.Interim,pddl.makeTest(refB,true)));
			}
			break;
		case Float:
			assert right.typeCode() == TypeCode.Float : "No operation combines floats and non-floats (at present).";
			PDDL.FunctionReference refF = (PDDL.FunctionReference) left.translateLValue(pddl,unit);
			PDDL.FloatExpression v = (PDDL.FloatExpression) right.translateExpr(pddl,unit);
			//conditions.add(pddl.wrap(pl,pddl.makeTest(PDDL.Op.lt,refF,??)));
			effects.add(pddl.makeEffect(pr,PDDL.Op.increase,refF,v)); // or could move it to pl, but this is the standard way
			// could add this constraint, but it would be better to just throw it in the domain action and be done with it once.
			//conditions.add(pddl.wrap(PDDL.Time.Interim/End,pddl.makeTest(PDDL.Op.gte,refF,pddl.Zero)));
			break;
		default:
			System.err.println("Oops!");
		}
	}

}
